﻿/**
 * Peter
 * Created by: Peter Development Team
 *    http://peter.codeplex.com/
 * 
 * GNU General Public License version 2 (GPLv2)
 *    http://peter.codeplex.com/license
 *
 *  This code is provided on an AS IS basis, with no WARRANTIES,
 *  CONDITIONS or GUARANTEES of any kind.
 *
 **/
using System;
using System.Windows.Controls;
using System.Windows.Input;
using ICSharpCode.AvalonEdit;
using Peter.Common;
using Peter.Common.Icons;
using Peter.Common.MainMenu;
using Peter.Data;
using Peter.DataAccess;
using Peter.DataAccess.EventArguments;
using Peter.Logic.AvalonEdit;
using Peter.Properties;

namespace Peter.Logic
{
   /// <summary>
   /// Actions and events pertaining to the console.
   /// </summary>
   public sealed class ModelApplicationOutput : EditablePeterToolWindow
   {
      private RelayCommand m_ClearCommand;
      private readonly ConsoleRedirection m_Redirection;
      private readonly ConsoleRedirection m_ErrorRedirection;
      private readonly ErrorLineHighlighter m_ErrorHighlighter;

      /// <summary>
      /// Initializes a new console model.
      /// </summary>
      public  ModelApplicationOutput ()
      {
         this.Title = "Output";
         this.Icon = MainMenuIcon.Colocation;
         this.ContentId = Guids.OUTPUT;
         this.ToolTip = Resources.ApplicationOutput;

         this.m_Redirection = new ConsoleRedirection ();
         this.m_ErrorRedirection = new ConsoleRedirection (true);
         Console.SetOut (this.m_Redirection);
         Console.SetError (this.m_ErrorRedirection);
         this.m_Redirection.LineWritten += this.OnLineWritten;
         this.m_ErrorRedirection.LineWritten += this.OnLineWritten;

         this.Editor = new TextEditor
         {
            Focusable = true,
            IsReadOnly = true,
            ContextMenu = new ContextMenu
            {
               Items =
               {
                  new MenuItem
                  {
                     Header = "Copy", 
                     Command = ApplicationCommands.Copy,
                     Icon = new IconDisplay {Icon = MainMenuIcon.Copy }
                  },
                  new MenuItem
                  {
                     Header = "Select All",
                     Command = ApplicationCommands.SelectAll,
                     Icon = new IconDisplay {Icon = MainMenuIcon.SelectionRectangleselection }
                  }
               }
            }
         };
         this.m_ErrorHighlighter = new ErrorLineHighlighter ();
         this.Editor.TextArea.TextView.LineTransformers.Add (this.m_ErrorHighlighter);
      }

      /// <summary>
      /// Gets the editor the output is writing to.
      /// </summary>
      public TextEditor Editor { get; private set; }

      /// <summary>
      /// Gets the command to clear the output.
      /// </summary>
      public ICommand ClearCommand
      {
         get { return m_ClearCommand ?? (this.m_ClearCommand = new RelayCommand (this.OnClear)); }
      }

      /// <summary>
      /// Clears the editor.
      /// </summary>
      /// <param name="obj">Command parameter.</param>
      private void OnClear (object obj)
      {
         this.m_ErrorHighlighter.LineNumbers.Clear ();
         this.Editor.Clear ();
      }

      /// <summary>
      /// Occurs when a line is written to the console.
      /// </summary>
      /// <param name="sender">Console Redirection.</param>
      /// <param name="args">Line written event arguments.</param>
      private void OnLineWritten (object sender, LineEventArgs args)
      {
         this.GuiDispatcher.Invoke (new Action <LineEventArgs> (this.OutputLine), args);
      }

      /// <summary>
      /// Outputs the given line.
      /// </summary>
      /// <param name="args">Line written event arguments.</param>
      private void OutputLine (LineEventArgs args)
      {
         this.Editor.AppendText (args.Line);
         if (args.IsError)
         {
            this.m_ErrorHighlighter.LineNumbers.Add (this.Editor.LineCount);
            this.Editor.TextArea.TextView.Redraw ();
         }
         this.Editor.ScrollToEnd ();
      }

      /// <summary>
      /// Performs the edit action.
      /// </summary>
      /// <param name="obj">Edit action.</param>
      protected override void OnEdit (object obj)
      {
         var editAction = (EditAction)obj;
         switch (editAction)
         {
            case EditAction.Copy:
               this.Editor.Copy ();
               break;
            case EditAction.SelectAll:
               this.Editor.SelectAll ();
               break;
         }
         base.OnEdit (obj);
      }
   }
}
